﻿using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Zip.Compression;
using ShiQuan.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace ShiQuan.AppUpdateBLL
{
    /// <summary>
    /// 文件辅助对象
    /// </summary>
    public class ZipFileHelper
    {
        /// <summary>
        /// 缓存大小
        /// </summary>
        private const int BUFFER_LENGTH = 4096;

        /// <summary>
        /// Zip文件压缩
        /// ZipOutputStream：相当于一个压缩包；
        /// ZipEntry：相当于压缩包里的一个文件；
        /// 以上两个类是SharpZipLib的主类。
        /// </summary>
        /// <param name="sourceFileLists"></param>
        /// <param name="descFile">压缩文件保存的目录</param>
        /// <param name="compression">压缩级别</param>
        public static void Compress(List<string> sourceFileLists, string descFile, int compression)
        {
            if (compression < 0 || compression > 9)
            {
                throw new ArgumentException("错误的压缩级别");
            }
            if (!Directory.Exists(new FileInfo(descFile).Directory.ToString()))
            {
                throw new ArgumentException("保存目录不存在");
            }
            foreach (string c in sourceFileLists)
            {
                if (!File.Exists(c))
                {
                    throw new ArgumentException(string.Format("文件{0} 不存在！", c));
                }
            }
            Crc32 crc32 = new Crc32();
            using (ZipOutputStream stream = new ZipOutputStream(File.Create(descFile)))
            {
                stream.SetLevel(compression);
                ZipEntry entry;
                for (int i = 0; i < sourceFileLists.Count; i++)
                {
                    entry = new ZipEntry(Path.GetFileName(sourceFileLists[i]));
                    entry.DateTime = DateTime.Now;
                    using (FileStream fs = File.OpenRead(sourceFileLists[i]))
                    {
                        byte[] buffer = new byte[fs.Length];
                        fs.Read(buffer, 0, buffer.Length);

                        entry.Size = fs.Length;

                        crc32.Reset();
                        crc32.Update(buffer);

                        entry.Crc = crc32.Value;

                        stream.PutNextEntry(entry);
                        stream.Write(buffer, 0, buffer.Length);
                    }
                    stream.CloseEntry();
                }

            }
        }

        /// <summary>
        /// 解压缩
        /// </summary>
        /// <param name="sourceFile">源文件</param>
        /// <param name="targetPath">目标路经</param>
        public static bool DeCompress(string sourceFile, string targetPath)
        {
            if (!File.Exists(sourceFile))
            {
                throw new FileNotFoundException(string.Format("未能找到文件 '{0}' ", sourceFile));
            }
            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }
            using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(sourceFile)))
            {
                ZipEntry theEntry;
                while ((theEntry = zipStream.GetNextEntry()) != null)
                {
                    string directorName = Path.Combine(targetPath, Path.GetDirectoryName(theEntry.Name));
                    // 创建目录
                    if (!Directory.Exists(directorName))
                    {
                        Directory.CreateDirectory(directorName);
                    }
                    if (theEntry.IsDirectory)
                    {
                        continue;
                    }
                    string fileName = Path.Combine(directorName, Path.GetFileName(theEntry.Name));
                    using (FileStream streamWriter = File.Create(fileName))
                    {
                        int size = 4096;
                        byte[] data = new byte[size];
                        while (true)
                        {
                            size = zipStream.Read(data, 0, data.Length);
                            if (size > 0)
                            {
                                streamWriter.Write(data, 0, size);
                            }
                            else break;
                        }
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// 字符串压缩
        /// </summary>
        /// <param name="text">待压缩的字符串</param>
        /// <returns>已压缩的字符串</returns>
        public static string Compress(string text)
        {
            string result = string.Empty;
            byte[] data = Encoding.UTF8.GetBytes(text);
            byte[] dData = Compress(data);
            result = Convert.ToBase64String(dData);
            Array.Clear(dData, 0, dData.Length);
            return result;
        }
        /// <summary>
        /// 字符串解压
        /// </summary>
        /// <param name="text">待解压的字符串</param>
        /// <returns>已解压的字符串</returns>
        public static string DeCompress(string text)
        {
            string result = string.Empty;
            byte[] data = Convert.FromBase64String(text);
            byte[] dData = DeCompress(data);
            result = Encoding.UTF8.GetString(dData);
            Array.Clear(dData, 0, dData.Length);
            return result;
        }

        /// <summary>
        /// 字节数组压缩
        /// </summary>
        /// <param name="data">待压缩的字节数组</param>
        /// <param name="isClearData">压缩完成后，是否清除待压缩字节数组里面的内容</param>
        /// <returns>已压缩的字节数组</returns>
        public static byte[] Compress(byte[] data, bool isClearData = true)
        {
            byte[] bytes = null;
            Deflater f = new Deflater(Deflater.BEST_COMPRESSION);
            f.SetInput(data);
            f.Finish();
            int count = 0;
            using (MemoryStream o = new MemoryStream(data.Length))
            {
                byte[] buffer = new byte[BUFFER_LENGTH];
                while (!f.IsFinished)
                {
                    count = f.Deflate(buffer);
                    o.Write(buffer, 0, count);
                }
                bytes = o.ToArray();
            }
            if (isClearData)
            {
                Array.Clear(data, 0, data.Length);
            }
            return bytes;
        }

        /// <summary>
        /// 字节数组解压缩
        /// </summary>
        /// <param name="data">待解压缩的字节数组</param>
        /// <param name="isClearData">解压缩完成后，是否清除待解压缩字节数组里面的内容</param>
        /// <returns>已解压的字节数组</returns>
        public static byte[] DeCompress(byte[] data, bool isClearData = true)
        {
            byte[] bytes = null;
            Inflater f = new Inflater();
            f.SetInput(data);
            int count = 0;
            using (MemoryStream o = new MemoryStream(data.Length))
            {
                byte[] buffer = new byte[BUFFER_LENGTH];
                while (!f.IsFinished)
                {
                    count = f.Inflate(buffer);
                    o.Write(buffer, 0, count);
                }
                bytes = o.ToArray();
            }
            if (isClearData)
            {
                Array.Clear(data, 0, count);
            }
            return bytes;
        }
        /// <summary>
        /// 复制文件
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="destPath"></param>
        public static void Copy(string sourcePath, string appLocalFile, string destPath, ref string appZipFile)
        {
            if (System.IO.Directory.Exists(destPath) == false)
                System.IO.Directory.CreateDirectory(destPath);

            string[] fileNames = System.IO.Directory.GetFiles(sourcePath);
            for (int i = 0; i < fileNames.Length; i++)
            {
                //System.IO.FileInfo fileInfo = new FileInfo(fileNames[i]);
                string fileName = System.IO.Path.GetFileName(fileNames[i]);
                string destFile = System.IO.Path.Combine(destPath, fileName);
                if (appLocalFile == destFile)
                {
                    appZipFile = fileNames[i];
                    continue;
                }
                Logger.Info("开始复制文件：" + fileNames[i] + " 到：" + destFile);
                System.IO.File.Copy(fileNames[i], destFile, true);
            }

            //复制子目录
            string[] mSubPaths = System.IO.Directory.GetDirectories(sourcePath);
            foreach (var item in mSubPaths)
            {
                System.IO.DirectoryInfo directInfo = new DirectoryInfo(item);

                string mSourcePath = System.IO.Path.Combine(sourcePath, directInfo.Name);
                string mDestPath = System.IO.Path.Combine(destPath, directInfo.Name);
                ZipFileHelper.Copy(mSourcePath, appLocalFile, mDestPath, ref appZipFile);
            }
            /*2021-06-26 侯连文 最后更新本地程序-程序信息文件*/
            if (System.IO.File.Exists(appZipFile))
            {
                Logger.Info("开始复制文件：" + appZipFile + " 到：" + appLocalFile);
                System.IO.File.Copy(appZipFile, appLocalFile, true);
            }
        }
    }
}
